<?php
namespace App\Common\Cla\Weixin\Pay\Order;

use App\Common as com;
use App\Common\Cla\Weixin\Pay as namePay;

class Unify extends namePay\Base\OfConfig {

	protected $param = [
		'outTradeNo' => null,
		'totalFee' => null,
		'body' => '商品支付',
		'notifyUrl' => null, // 需传入完整的域名地址
		'tradeType' => 'JSAPI',
		'openid' => null,
	];

	/**
	 * Unify constructor.
	 * @param string $openid
	 * @param string $outTradeNo 订单编号
	 * @param int $totalFeeCents 订单总金额，单位为分
	 * @throws
	 */
	public function __construct( namePay\OfConfig $configObj, string $openid, string $outTradeNo, int $totalFeeCents ) {
		$this->param['openid'] = $openid;
		$this->param['outTradeNo'] = $outTradeNo;
		$this->param['totalFee'] = $totalFeeCents;
		$this->param['notifyUrl'] = com\Lib\Hyperf\Config::getWebUrlOrFail() . '/appCharging/wxPayNotify';
		//
		parent::__construct( $configObj );
	}

	public function setOutTradeNo( string $outTradeNo ):self {
		$this->param['outTradeNo'] = $outTradeNo;
		//
		return $this;
	}

	public function getOutTradeNo(  ):string {
		return $this->param['outTradeNo'];
	}

	public function setTotalFee( int $totalFee ):self {
		$this->param['totalFee'] = $totalFee;
		//
		return $this;
	}

	public function getTotalFee(  ):int {
		return $this->param['totalFee'];
	}

	public function setBody( string $body ):self {
		$this->param['body'] = $body;
		//
		return $this;
	}

	public function getBody(  ):string {
		return $this->param['body'];
	}

	public function setOpenid( string $openid ):self {
		$this->param['openid'] = $openid;
		//
		return $this;
	}

	public function getOpenid(  ):string {
		return $this->param['openid'];
	}

	/**
	 * 设置->回调
	 * @param string $notifyUrl 需传入完整的域名地址
	 * @return $this
	 */
	public function setNotifyUrl( string $notifyUrl ):self {
		$this->param['notifyUrl'] = $notifyUrl;
		//
		return $this;
	}

	public function getNotifyUrl(  ):string {
		return $this->param['notifyUrl'];
	}

	public function setTradeType( string $tradeType ):self {
		$this->param['tradeType'] = $tradeType;
		//
		return $this;
	}

	public function getTradeType(  ):string {
		return $this->param['tradeType'];
	}

	/**
	 * 统一下单
	 * @return array 调用成功时会返回带有'prepay_id'键名的数组
	 * 返回数据示例：
	 * array(9) {
	 * 		["return_code"] => string(7) "SUCCESS"
	 * 		["return_msg"] => string(2) "OK"
	 * 		["appid"] => string(18) "wxf6d9b03be96ec2cd"
	 * 		["mch_id"] => string(10) "1532730001"
	 * 		["nonce_str"] => string(16) "aD60LcHZWdMLTuYa"
	 * 		["sign"] => string(32) "2435312264AC3C3AE87B3D166296B8F3"
	 * 		["result_code"] => string(7) "SUCCESS"
	 * 		["prepay_id"] => string(36) "wx031605148298781e381ad76a1479313652"
	 *		["trade_type"] => string(5) "JSAPI"
	 * }
	 * @throws
	 */
	public function commitUnify(  ):array {
		$attr = [
			'out_trade_no' => $this->getOutTradeNo(),
			'total_fee' => $this->getTotalFee(),
			'body' => $this->getBody(),
			'notify_url' => $this->getNotifyUrl(),
			'trade_type' => $this->getTradeType(),
			'openid' => $this->getOpenid(),
		];
		//
		$unifyRes = $this->getEasyObj()->order->unify( $attr );
		// 检查结果
		if( $unifyRes['result_code'] !== 'SUCCESS' ){
			d([
				'提交支付失败',
				$unifyRes
			]);
			throw com\Lib\Err\Exception::makeOfNew( '提交支付失败，' . $unifyRes['result_code'], com\Lib\Err\Code::$sysAssertError );
		}
		//
		return $unifyRes;
	}

	/**
	 * 统一下单并返回小程序支付参数
	 * @return array
	 * @throws com\Lib\Err\BaseException\Throw_
	 * @throws com\Lib\Err\Exception
	 */
	public function commitUnifyReMiniProgramPayParam(  ):array {
		$unifyRes = $this->commitUnify();
		//
		return $this->buildMiniProgramPayParam( $unifyRes['nonce_str'], $unifyRes['prepay_id'] );
	}

	/**
	 * 统一下单并返回jssdk支付参数
	 * @return array
	 * @throws com\Lib\Err\BaseException\Throw_
	 * @throws com\Lib\Err\Exception
	 */
	public function commitUnifyReJssdkPayParam(  ):array {
		$unifyRes = $this->commitUnify();
		//
		return $this->getEasyObj()->jssdk->sdkConfig( $unifyRes['prepay_id'] );
	}

	/**
	 * 生成小程序支付参数
	 * @param string $nonceStr
	 * @param string $prepayId
	 * @param string $signType
	 * @param string|null $timeStamp
	 * @return array
	 */
	private function buildMiniProgramPayParam( string $nonceStr, string $prepayId, string $signType = 'MD5', string $timeStamp = null ):array {
		// ...
		$timeStamp ??= com\Lib\Fun\Time::getTime();
		//
		$appId = $this->getConfigObj()->getEasyConfig()['app_id'];
		$key = $this->getConfigObj()->getEasyConfig()['key'];
		//
		$md5Str = 'appId=' . $appId;
		$md5Str .= '&nonceStr=' . $nonceStr;
		$md5Str .= '&package=prepay_id=' . $prepayId;
		$md5Str .= '&signType=' . $signType;
		$md5Str .= '&timeStamp=' . $timeStamp;
		$md5Str .= '&key=' . $key;
		//
		return [
			'nonceStr' => $nonceStr,
			'package' => 'prepay_id=' . $prepayId,
			'signType' => $signType,
			'timeStamp' => (string)$timeStamp,
			'paySign' => md5( $md5Str ),
		];
	}

	// ===============================
	//
	//
	// 下面为静态方法
	//
	//
	// ===============================

	/**
	 * @param namePay\OfConfig $configObj
	 * @param string $openid
	 * @param string $outTradeNo
	 * @param int $totalFeeCents
	 * @return $this
	 */
	public static function makeOfNew( namePay\OfConfig $configObj, string $openid, string $outTradeNo, int $totalFeeCents ):self {
	    return self::make( ...func_get_args() );
	}

}
